package bn;

import java.util.Iterator;
import java.util.Vector;

import env.City;
import env.Road;
import env.World;
import main.Main;

public class Inference
{
	public static void reportInference(City city)
	{
		// TODO i am not sure this is even needed
		if (city.getChemsReported() == 1)
			System.out.println("P(report in " + city.getName() + ") = <1,0>");
		else
		{ 
			if (city.getChemsReported() == 0 || city.getChems() == 0)
				System.out.println("P(report in " + city.getName() + ") = <0,1>");
			else
			{
				if (city.getChems() == -1)
					System.out.println("P(report in " + city.getName() + ") = <"
							+ city.bChemNode.son.p + "," + (1 - city.bChemNode.son.p) + ">");
				else
					System.out.println("P(report in " + city.getName() + ") = <" + Main.pReveal
							+ "," + (1 - Main.pReveal) + ">");

			}
		}
	}

	public static void chemsInference(City city)
	{
		if (city.getChems() == 1)
			System.out.println("P(chems in " + city.getName() + ") = <1,0>");
		else
		{
			if (city.getChems() == 0)
				System.out.println("P(chems in " + city.getName() + ") = <0,1>");
			else
				System.out.println("P(chems in " + city.getName() + ") = <" + Main.pChem + ","
						+ (1 - Main.pChem) + ">");
		}

	}

	public static void armyInference(City city)
	{

		if (city.getEscorts() == 1)
			System.out.println("P(army in " + city.getName() + ") = <1,0>");
		else
		{
			if (city.getEscorts() == 0)
				System.out.println("P(army in " + city.getName() + ") = <0,1>");
			else
				System.out.println("P(army in " + city.getName() + ") = <" + Main.pArmy + ","
						+ (1 - Main.pArmy) + ">");
		}

	}

/*	public static void terroristInference(Road road)
	{
		// System.out.print(road.bTerroristNode.output());
		double p;
		if(road.getEvBlocked()==-1)
			p = rejectionSample(road, 10000);
		else
			p=road.getEvBlocked();
		System.out.println("P (Terrorist in road" + road.getName() + ")= <" + TerroristNode.round(p,2) + "," + TerroristNode.round((1 - p),2)
				+ ">)");
	}

	
	private static double rejectionSample(Road road, int count)
	{
		int terroristTrue = 0, terroristFalse = 0;
		for (int i = 0; i < count; i++)
		{

			boolean reject = false;
			int sample = 0;
			if (Math.random() < Main.pArmy)
			{
				if (road.getE1().getEscorts() == 0)
					reject = true;
				else
					sample += TerroristNode.armyA;
			} else if (road.getE1().getEscorts() == 1)
				reject = true;
			if (Math.random() < Main.pArmy)
			{
				if (road.getE2().getEscorts() == 0)
					reject = true;
				else
					sample += TerroristNode.armyB;
			} else if (road.getE2().getEscorts() == 1)
				reject = true;

			if (Math.random() < Main.pChem)
			{
				if (road.getE1().getChems() == 0)
					reject = true;
				else
				{
					if (Math.random() < road.getE1().bChemNode.son.getP(true))
					{
						if (road.getE1().getChemsReported() == 1)
							sample += TerroristNode.chemA;
						else
							reject = true;
					}
				}
			} else if (road.getE1().getChems() == 1)
				reject = true;
			if (Math.random() < Main.pChem)
			{
				if (road.getE2().getChems() == 0)
					reject = true;
				else
				{
					if (Math.random() < road.getE2().bChemNode.son.getP(true))
					{
						if (road.getE2().getChemsReported() == 1)
							sample += TerroristNode.chemB;
						else
							reject = true;
					}
				}
			} else if (road.getE1().getChems() == 1)
				reject = true;
	
			if (!reject)
			{
				if (Math.random() < road.bTerroristNode.getP(sample))
					terroristTrue++;
				else
					terroristFalse++;
			}
		}
		//System.out.println(terroristFalse+":"+terroristTrue);
		return (double)terroristTrue / (terroristTrue + terroristFalse);
	}
*/
	private static double rejectionSample(World world, Vector<Road> roads, int count)
	{
		boolean terroristTrue[] = new boolean[roads.size()];
		int pathClear = 0, pathBlocked = 0;
		boolean[] chems, chemReports, armys;
		boolean reject = false;
		Iterator<Road> it = roads.iterator();
		while (it.hasNext())
		{
			if (it.next().getEvBlocked() == 1)
				return 1;
		}
		for (int i = 0; i < count; i++)
		{

			reject = false;
			chems = new boolean[world.getCities().size()];
			armys = new boolean[world.getCities().size()];
			chemReports = new boolean[world.getCities().size()];
			for (int j = 0; j < armys.length && !reject; j++)
			{
				City city = world.getCityByName(Integer.toString(j+1));
				armys[j] = (Math.random() < Main.pArmy);
				if (city.getEscorts() != -1)
					reject = armys[j] ^ (city.getEscorts() == 1);
				chems[j] = (Math.random() < Main.pChem);
				if (city.getChems() != -1)
					reject = reject || (chems[j] ^ (city.getChems() == 1));
				if (chems[j])
					chemReports[j] = (Math.random() < world.getCityByName(Integer.toString(j+1)).bChemNode.son.getP(true));
				if(city.getChemsReported()!=-1)
					reject = reject || (chemReports[j] ^ (city.getChemsReported() == 1));
			}
			it = roads.iterator();
			int k = 0;
			while (it.hasNext() && !reject)
			{
				Road road = it.next();
				int sample = 0, c1 = Integer.parseInt(road.getE1().getName())-1, c2 = Integer
						.parseInt(road.getE2().getName())-1;
				sample += chemReports[c1] ? TerroristNode.chemA : 0;
				sample += chemReports[c2] ? TerroristNode.chemB : 0;
				sample += armys[c1] ? TerroristNode.armyA : 0;
				sample += armys[c2] ? TerroristNode.armyB : 0;
				
				double p = road.bTerroristNode.getP(sample);
				terroristTrue[k] = (Math.random() < p);
				if (road.getEvBlocked() != -1)
					reject = (reject || (terroristTrue[k] ^ (road.getEvBlocked() == 1)));
				k++;
			}
			for (int l = 0; l < terroristTrue.length && !reject; l++)
			{
				if (terroristTrue[l])
				{
					reject = true;
					pathBlocked++;
				}
			}
			if (!reject)
				pathClear++;

		}
		//System.out.println(pathClear+":"+pathBlocked);
		return (double) pathBlocked / (pathBlocked + pathClear);
	}

	public static void terroristInference(World world, Vector<Road> roads)
	{
		// System.out.print(road.bTerroristNode.output());
				double p = rejectionSample(world,roads, 100000);
				System.out.println("P (Terrorist in path)= <" + TerroristNode.round(p,2) + "," + TerroristNode.round(1-p,2)+ "> (rejection)");
				p=wLikely(world, roads,100000);
				System.out.println("P (Terrorist in path)= <" + TerroristNode.round(p,2) + "," + TerroristNode.round(1-p,2)+ "> (likelyhood)");

		
	}

	private static double wLikely(World world, Vector<Road> roads, int count)
	{
		boolean terroristTrue[] = new boolean[roads.size()];
		double pathClear = 0, pathBlocked = 0;
		boolean[] chems, chemReports, armys;
//		boolean reject = false;
		Iterator<Road> it = roads.iterator();
		while (it.hasNext())
		{
			if (it.next().getEvBlocked() == 1)
				return 1;
		}
		for (int i = 0; i < count; i++)
		{
	
//			reject = false;
			double w = 1;
			chems = new boolean[world.getCities().size()];
			armys = new boolean[world.getCities().size()];
			chemReports = new boolean[world.getCities().size()];
			for (int j = 0; j < armys.length; j++)
			{
				
				City city = world.getCityByName(Integer.toString(j+1));
				if (city.getEscorts() == -1)
					armys[j] = (Math.random() < Main.pArmy);
				else 
				{
					w *= city.getEscorts() == 1 ? Main.pArmy : 1 - Main.pArmy;
					armys[j] = (city.getEscorts() == 1);
				}
				if (city.getChems() == -1)
					chems[j] = (Math.random() < Main.pChem);
				else
				{
					w *= city.getChems() == 1 ? Main.pChem : 1 - Main.pChem;
					chems[j] = (city.getChems() == 1);
				}
				if (chems[j])
				{
					if(city.getChemsReported()== -1)
						chemReports[j] = (Math.random() < world.getCityByName(Integer.toString(j+1)).bChemNode.son.getP(true));
					else
					{
						w *= city.getChemsReported() == 1 ? Main.pReveal: 1 - Main.pReveal;
						chemReports[j] = (city.getChemsReported() == 1);
					}
				}
			}
			it = roads.iterator();
			int k = 0;
			while (it.hasNext())
			{
				Road road = it.next();
				int sample = 0, c1 = Integer.parseInt(road.getE1().getName()) - 1, c2 = Integer
						.parseInt(road.getE2().getName()) - 1;
				sample += chemReports[c1] ? TerroristNode.chemA : 0;
				sample += chemReports[c2] ? TerroristNode.chemB : 0;
				sample += armys[c1] ? TerroristNode.armyA : 0;
				sample += armys[c2] ? TerroristNode.armyB : 0;
				
				double p = road.bTerroristNode.getP(sample);
				
				if (road.getEvBlocked() == -1)
					terroristTrue[k] = (Math.random() < p);
				else 
				{
					w *= road.getEvBlocked() == 1 ? p : 1 - p;
					terroristTrue[k] = (road.getEvBlocked() == 1);
				}
					
				k++;
			}
			boolean blocked = false;
			for (int l = 0; l < terroristTrue.length; l++)
			{
				if (terroristTrue[l])
				{
					
					pathBlocked += w;
					blocked = true;
					break;
				}
			}
			if (!blocked)
				pathClear += w;
	
		}
//		System.out.println(pathClear+":"+pathBlocked);
		return pathBlocked / (pathBlocked + pathClear);
	}
}
